package com.carleasoft.mps.cms.business.fileUpload.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.cms.business.article.constants.ExceptionCMSEnum;
import com.carleasoft.mps.cms.business.fileUpload.bean.entity.InformationLibrary;
import com.carleasoft.mps.cms.business.fileUpload.bean.entity.InformationTypeEntity;
import com.carleasoft.mps.cms.business.fileUpload.bean.vo.InformationTypeVo;
import com.carleasoft.mps.cms.business.fileUpload.dao.InformationTypeMapper;
import com.carleasoft.mps.cms.business.fileUpload.service.InformationLibraryService;
import com.carleasoft.mps.cms.business.fileUpload.service.InformationTypeService;
import com.carleasoft.mps.core.exceptions.BusinessException;
import com.carleasoft.mps.core.user.ThreadUserContext;
import com.carleasoft.mps.core.user.UserCacheData;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @author: yangHao
 * @createDate:2023/6/6
 * @description:
 */
@Service
public class InformationTypeServiceImpl extends ServiceImpl<InformationTypeMapper, InformationTypeEntity> implements InformationTypeService {
    @Autowired
    private InformationLibraryService informationLibraryService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveType(InformationTypeEntity informationTypeEntity) {
        boolean isOk = false;
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        informationTypeEntity.setCreateTime(LocalDateTime.now());
        informationTypeEntity.setCreatePersonCode(user.getUserCode());
        informationTypeEntity.setCreatePersonName(user.getUserName());
        String idStr = IdWorker.getIdStr();
        if (StrUtil.isBlank(informationTypeEntity.getParentTypeCode())) {
            informationTypeEntity.setParentTypeCode("0");
            informationTypeEntity.setFullPath(informationTypeEntity.getInformationTypeCode());
        } else {
            if (informationTypeEntity.getParentTypeCode().equals("0")) {
                informationTypeEntity.setFullPath(informationTypeEntity.getInformationTypeCode());

            } else {
                InformationTypeEntity typeEntity = this.getOne(Wrappers.<InformationTypeEntity>lambdaQuery()
                        .eq(InformationTypeEntity::getInformationTypeCode, informationTypeEntity.getParentTypeCode()));
                informationTypeEntity.setFullPath(typeEntity.getFullPath() + "&" + informationTypeEntity.getInformationTypeCode());

            }

        }
        if (StrUtil.isBlank(informationTypeEntity.getInformationTypeCode())) {
            informationTypeEntity.setInformationTypeCode(idStr);
            isOk = this.save(informationTypeEntity);
        } else {
            InformationTypeEntity one = this.getOne(Wrappers.<InformationTypeEntity>lambdaQuery()
                    .eq(InformationTypeEntity::getInformationTypeCode, informationTypeEntity.getInformationTypeCode()));
            informationTypeEntity.setId(one.getId());
            isOk = this.updateById(informationTypeEntity);
        }
        return isOk;
    }

    @Override
    public List<InformationTypeVo> tree(InformationTypeEntity informationTypeEntity) {
        List<InformationTypeVo> informationTypeVos = new ArrayList<>();
        List<InformationTypeEntity> list = this.list();
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(i -> {

                informationTypeVos.add(BeanUtil.copyProperties(i, InformationTypeVo.class));
            });
        }
        return this.buildTree(informationTypeVos);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(InformationTypeEntity informationTypeEntity) {
        InformationTypeEntity typeEntity = this.getOne(Wrappers.<InformationTypeEntity>lambdaQuery()
                .eq(InformationTypeEntity::getInformationTypeCode, informationTypeEntity.getInformationTypeCode()));
        List<InformationLibrary> informationLibraries = informationLibraryService.list(Wrappers.<InformationLibrary>lambdaQuery()
                .eq(InformationLibrary::getTypeCode, typeEntity.getInformationTypeCode()));
        if (CollUtil.isNotEmpty(informationLibraries)) {
            throw new BusinessException(ExceptionCMSEnum.NO_DELETE);
        }
        List<InformationTypeEntity> informationTypeEntities = this.list(Wrappers.<InformationTypeEntity>lambdaQuery()
                .eq(InformationTypeEntity::getParentTypeCode, typeEntity.getInformationTypeCode())
                .ne(InformationTypeEntity::getParentTypeCode, 0));
        this.listDelete(informationTypeEntities);
        return this.remove(Wrappers.<InformationTypeEntity>lambdaQuery()
                .eq(InformationTypeEntity::getInformationTypeCode, informationTypeEntity.getInformationTypeCode()));
    }


    public void listDelete(List<InformationTypeEntity> informationTypeEntities) {
        if (CollUtil.isNotEmpty(informationTypeEntities)) {
            for (InformationTypeEntity informationTypeEntity : informationTypeEntities) {
                List<InformationLibrary> informationLibraries = informationLibraryService.list(Wrappers.<InformationLibrary>lambdaQuery()
                        .eq(InformationLibrary::getTypeCode, informationTypeEntity.getInformationTypeCode()));
                if (CollUtil.isNotEmpty(informationLibraries)) {
                    throw new BusinessException(ExceptionCMSEnum.NO_DELETE);
                }
                List<InformationTypeEntity> informationTypeEntityList = this.list(Wrappers.<InformationTypeEntity>lambdaQuery()
                        .eq(InformationTypeEntity::getParentTypeCode, informationTypeEntity.getInformationTypeCode())
                        .ne(InformationTypeEntity::getParentTypeCode, 0));
                if (CollUtil.isNotEmpty(informationTypeEntityList)) {
                    this.listDelete(informationTypeEntityList);
                } else {
                    break;
                }

            }
        }
    }


    //解析并找到父节点
    private List<InformationTypeVo> buildTree(List<InformationTypeVo> list) {
        //找出顶级节点编码
        Set<String> pList = list.stream().collect(Collectors.groupingBy(InformationTypeVo::getParentTypeCode)).keySet();
        Set<String> cList = list.stream().collect(Collectors.groupingBy(InformationTypeVo::getInformationTypeCode)).keySet();
        List<String> topList = pList.stream().filter(item -> !cList.contains(item)).collect(toList());

        List<InformationTypeVo> last = new ArrayList<>();
        for (String parentCode : topList) {
            last.addAll(this.getTreeListFromCurrent(parentCode, list));
        }
        return last;
    }

    /**
     * 解析树形数据
     *
     * @param currentId
     * @param entityList
     * @return
     */
    public List<InformationTypeVo> getTreeListFromCurrent(String currentId, List<InformationTypeVo> entityList) {

        if (entityList == null || entityList.size() == 0) return new ArrayList<>();

        List<InformationTypeVo> resultList = new ArrayList<>();

        //获取顶层元素集合
        for (InformationTypeVo entity : entityList) {
            if (currentId.equals(entity.getParentTypeCode())) {
                resultList.add(entity);
            }
        }

        //获取每个顶层元素的子数据集合
        for (InformationTypeVo entity : resultList) {
            entity.setChildren(getSubList(entity.getInformationTypeCode(), entityList));
        }
        return resultList;
    }

    /**
     * 获取子数据集合
     *
     * @param deptCode
     * @param subList
     */
    private List<InformationTypeVo> getSubList(String deptCode, List<InformationTypeVo> subList) {
        List<InformationTypeVo> childList = new ArrayList<>();
        //子集的直接子对象
        for (InformationTypeVo entity : subList) {
            if (deptCode.equals(entity.getParentTypeCode())) {
                childList.add(entity);
            }
        }
        //递归退出条件
        if (childList.size() == 0) {
            return null;
        }
        //子集的间接子对象
        for (InformationTypeVo entity : childList) {
            entity.setChildren(getSubList(entity.getInformationTypeCode(), subList));
        }

        return childList;
    }

}
